﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Input;
using UtilityLibrary;
using FarseerPhysics.Common;
using Animation;
using Physics;

namespace MapLibrary
{
    /// <summary>
    /// Manages the addition of new collision objects to the Level
    /// </summary>
    public class CollisionObjectManager
    {
        private const int DEFAULT_RECT_SIZE = 50;

        public enum EditingMode { Hull, Selection };

        private Texture2D point;

        /// <summary>
        /// Current editing mode
        /// </summary>
        private EditingMode Mode;

        /// <summary>
        /// The level we are modifying
        /// </summary>
        private Level toEdit;

        private CollisionObject selection;

        /// <summary>
        /// Holds the temporary convex hull points until user is done adding them all.
        /// When the user is done, the convex hull of the points provided will become the
        /// new CollisionObject deep check.
        /// 
        /// Note that it is assumed that these points in fact are the unique points
        /// on the convex hull, and that they are in order along the hull.
        /// </summary>
        //private List<Vector2> temporaryHullPoints;
        private EditorConvexHull temporaryHullPoints;

        /// <summary>
        /// Holds the temporary AABB shallow check rectangle.
        /// </summary>
        //private CollisionRectangle temporaryRectangle;

        public CollisionObjectManager()
        {
            temporaryHullPoints = new EditorConvexHull();

            Mode = EditingMode.Hull;
            selection = null;
        }

        public void LoadContent(ContentManager content)
        {
            point = content.Load<Texture2D>(@"./LevelEditor/Point");
        }

        public void EditLevel(Level pLevel)
        {
            toEdit = pLevel;
        }

        /// <summary>
        /// Draws all of the CollisionObjects in Level with their bounding boxes.  Also draws
        /// </summary>
        /// <param name="batch"></param>
        public void Draw(SpriteBatch batch, WorldViewport viewport)
        {
            foreach (CollisionObject obj in toEdit.CollisionObjectsEnum())
            {
                if(obj != selection)
                    DrawCollisionObject(obj, batch, viewport);
            }

            temporaryHullPoints.EditorDraw(batch, viewport);

            if(Mode == EditingMode.Hull)
                PrimitiveBrush.RenderText(batch, "Convex Hull Edit", Vector2.Zero);
            else
                PrimitiveBrush.RenderText(batch, "Selection Edit", Vector2.Zero);
        }

        public void PlaceObject(Vector2 Position)
        {
            if (Mode == EditingMode.Selection)
            {

            }
            temporaryHullPoints.AddPoint(Position);
        }

        public EditingMode EditMode
        {
            get { return Mode; }
        }

        /// <summary>
        /// Build the CollisionObject and place it into the Level.
        /// </summary>
        public void FinalizeCollisionObject(WorldViewport viewport)
        {
            if (Mode == EditingMode.Hull)
            {
                if (temporaryHullPoints.Count <= 2)
                    return;

                CollisionObject obj = new CollisionObject();
                obj.Hull = this.temporaryHullPoints.ToVertices();

                toEdit.AddCollisionObject(obj);

                temporaryHullPoints.Clear();
            }
            else
            {
                selection.Hull = temporaryHullPoints.ToVertices();
                selection = null;
                temporaryHullPoints.Clear();
            }
        }

        //public void FinalizeCollisionObject(WorldViewport viewport, Sprite sprite)
        //{
        //    if (Mode == EditingMode.Hull)
        //    {
        //        if (temporaryHullPoints.Count <= 2)
        //            return;

        //        CollisionObject obj = new CollisionObject();
        //        obj.Hull = this.temporaryHullPoints.ToVertices();

        //        sprite.CollisionObject = obj;
        //        //toEdit.AddCollisionObject(obj);

        //        temporaryHullPoints.Clear();
        //    }
        //    else
        //    {
        //        selection.Hull = temporaryHullPoints.ToVertices();
        //        selection = null;
        //        temporaryHullPoints.Clear();
        //    }
        //}

        public void SetSelection(GameInput input, WorldViewport viewport)
        {
            if (Mode == EditingMode.Selection && selection == null)
            {
                Vector2 mouseWorldCoords = viewport.ViewportCoordsToWorldCoords(input.GetMousePosition());

                foreach (CollisionObject obj in toEdit.CollisionObjectsEnum())
                {
                    if (obj.Hull.PointInPolygon(ref mouseWorldCoords) == 1)
                    {
                        Select(obj);
                        break;
                    }
                }
            }
        }

        private void Select(CollisionObject obj)
        {
            selection = obj;
            temporaryHullPoints = new EditorConvexHull(selection.Hull);
        }

        /// <summary>
        /// Gets the collision object that is being hovered over.  This is highly dependent on the current editing mode.
        /// 
        /// EditingMode.Hull: Here there are two possible things that can be hovered.  First, we have the hull points that
        /// can be moved around, but not scaled nor rotated.  Similarly, if the mouse isn't over any of the points but within
        /// the hull, then the mouse can move the whole hull around.
        /// 
        /// EditingMode.Rectangle: Here there is only one possibility for the Hoverable.  In this case, it is the rectangle.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="viewport"></param>
        /// <returns></returns>
        public ITransformable GetHover(GameInput input, WorldViewport viewport)
        {
            return temporaryHullPoints.GetHoveredNode(input, viewport);
        }

        public void SwitchEditingMode()
        {
            if (Mode == EditingMode.Hull)
            {
                Mode = EditingMode.Selection;
            }
            else
            {
                Mode = EditingMode.Hull;
                selection = null;
                temporaryHullPoints.Clear();
            }
        }

        private void DrawCollisionObject(CollisionObject obj, SpriteBatch batch, WorldViewport viewport)
        {
            Vertices hull = obj.Hull;

            EditorConvexHull temp = new EditorConvexHull(hull);
            temp.EditorDraw(batch, viewport, Color.Blue);
        }

        private void SetEditingMode(EditingMode newmode)
        {
            this.Mode = newmode;
        }
    }
}
